/**
 * 
 */
package org.cmcc.pcap.jpcap.tcp.http;

import java.util.ArrayList;



import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import org.cmcc.pcap.jpcap.tcp.TcpConnection;
import org.cmcc.pcap.jpcap.tcp.TcpPacketDecorator;
import org.cmcc.pcap.jpcap.util.PacketAnalysisConfig;

/**
 * @Date 2018年5月14日 下午6:20:36
 * @author Amish
 */
public class HttpTransaction {
	
	public TcpConnection tcpConnection;
	
	/**
	 * TODO
	 * UL Data上行流量
	 * DL Data下行流量
	 * UL IP Packet上行IP包数
	 * DL IP Packet下行IP包数
	 * UL Disorder IP Packet上行TCP乱序报文数
	 * DL Disorder IP Packet下行TCP乱序报文数
	 * UL Retrans IP Packet上行TCP重传报文数
	 * DL Retrans IP Packet下行TCP重传报文数
	 * UL_IP_FRAG_PACKETS上行IP包的分片数
	 * DL_IP_FRAG_PACKETS下行IP包的分片数
	 * TCP SYN Num：TCP SYN次数
	 * TCP SYN ACK Num：TCP SYN ACK的次数
	 * TCP ACK Num：回复SYN ACK的ACK次数
	 * 
	 * 
	 */
	public static Logger logger = LogManager.getLogger(HttpTransaction.class);
	
	public int UL_Data=0;
	public int DL_Data=0;//单位为字节
	public int UL_IP_Packet=0;
	public int DL_IP_Packet=0;
	public int UL_Disorder_IP_Packet=0;
	public int DL_Disorder_IP_Packet=0;
	public int UL_Retrans_IP_Packet=0;
	public int DL_Retrans_IP_Packet=0;
	public int UL_IP_FRAG_PACKETS=0;
	public int DL_IP_FRAG_PACKETS=0;
	public int TCP_SYN_Num=0;
	public int TCP_SYN_ACK_Num=0;
	public int TCP_ACK_Num=0;//三次握手中回复SYN_ACK的ACK消息
	
	public int max_DL_Data=0;
	public long timestamp_DL_Data;
	public boolean isOverThreshold=false;
	public int DL_Retrans_Data=0;
	public ArrayList<TcpPacketDecorator> al_splited;
	
	public HttpTransaction(TcpConnection tcpConnection) {
		this.tcpConnection = tcpConnection;
		al_splited = new ArrayList<>();
		max_DL_Data = PacketAnalysisConfig.getConfigAsInt("tcp.packet.dl.threshold")*1024;//配置文件的单位是KByte，转换成Byte
	}	
	
	public void  HttpStatistics (TcpConnection tcpConnection){
        long SYN_ACK_seq_num=Long.MAX_VALUE;
        long SYN_seq_num=Long.MAX_VALUE;
		for(TcpPacketDecorator tcp_packet_decorator:al_splited){
			String src_Addr = String.valueOf(tcp_packet_decorator.tcpPacket.src_ip)+":"+String.valueOf(tcp_packet_decorator.tcpPacket.src_port);
			String dst_Addr = String.valueOf(tcp_packet_decorator.tcpPacket.dst_ip)+":"+String.valueOf(tcp_packet_decorator.tcpPacket.dst_port);
			if((src_Addr.equals("/"+tcpConnection.clientAddr)) && (dst_Addr.equals("/"+tcpConnection.serverAddr))){
				UL_IP_Packet++;
				UL_Data += tcp_packet_decorator.tcpPacket.length;
				if(tcp_packet_decorator.isDuplicateAckMerge){
					UL_IP_Packet+=tcp_packet_decorator.duplicateAckMergeAl.size();
				}
				if(tcp_packet_decorator.isOutOfOrder){
					UL_Disorder_IP_Packet++;
				}
				if(tcp_packet_decorator.isRetransmissionMerge){
					this.RetransPacket_Statistic(tcp_packet_decorator, 0);
				}
				if(tcp_packet_decorator.tcpPacket.more_frag||((!tcp_packet_decorator.tcpPacket.more_frag)&&(tcp_packet_decorator.tcpPacket.offset!=0))){
					UL_IP_FRAG_PACKETS++;
					logger.debug("find a upload ip frag"+tcp_packet_decorator.tcpPacket.sequence);
				}
				if(tcp_packet_decorator.isReassemble){
					this.ReassemblePacket_Statistic (tcp_packet_decorator, 0);
				}
			}
			else if((src_Addr.equals("/"+tcpConnection.serverAddr))&&(dst_Addr.equals("/"+tcpConnection.clientAddr))){
				DL_IP_Packet++;
				DL_Data += tcp_packet_decorator.tcpPacket.length;
				//判断是否超过下行流量阈值：数据包个数超过阈值/ip包的MTU、下行流量超过阈值、截止到上一个数据包还没超过阈值
				if((DL_IP_Packet>=max_DL_Data/1480)&&(DL_Data>=max_DL_Data)&&(isOverThreshold==false)){
					isOverThreshold=true;
					timestamp_DL_Data = tcp_packet_decorator.tcpPacket.sec*1000+tcp_packet_decorator.tcpPacket.usec;
				}
				if(tcp_packet_decorator.isDuplicateAckMerge){
					DL_IP_Packet+=tcp_packet_decorator.duplicateAckMergeAl.size();
				}
				if(tcp_packet_decorator.isOutOfOrder){
					DL_Disorder_IP_Packet++;
				}
				if(tcp_packet_decorator.isRetransmissionMerge){
					this.RetransPacket_Statistic(tcp_packet_decorator, 1);
				}
				if(tcp_packet_decorator.tcpPacket.more_frag||((!tcp_packet_decorator.tcpPacket.more_frag)&&(tcp_packet_decorator.tcpPacket.offset!=0))){
					DL_IP_FRAG_PACKETS++;
					logger.debug("find a download ip frag"+tcp_packet_decorator.tcpPacket.sequence);
				}
				if(tcp_packet_decorator.isReassemble){
					this.ReassemblePacket_Statistic(tcp_packet_decorator, 1);
				}
			}
//			三次握手：
//			Client --> 置SYN标志 序列号 = J，确认号 = 0 ----> Server
//			Client <-- 置SYN标志 置ACK标志 序列号 = K, 确认号 = J + 1 <-- Server
//			Clinet --> 置ACK标志 序列号 = J + 1，确认号 = K + 1 --> Server
			if (tcp_packet_decorator.tcpPacket.syn && tcp_packet_decorator.tcpPacket.ack_num==0){
				TCP_SYN_Num++;
				SYN_seq_num= tcp_packet_decorator.tcpPacket.sequence;
//				logger.debug("find syn request: "+tcp_packet_decorator.tcpPacket.sequence+" "+tcp_packet_decorator.tcpPacket.ack_num);
				continue;
			}
			else if (tcp_packet_decorator.tcpPacket.syn && (tcp_packet_decorator.tcpPacket.ack_num==SYN_seq_num+1)){
				TCP_SYN_ACK_Num++;				
				SYN_ACK_seq_num=tcp_packet_decorator.tcpPacket.sequence;//记录SYN_ACK消息序列号
//				logger.debug("find syn ack response: "+tcp_packet_decorator.tcpPacket.sequence+" "+tcp_packet_decorator.tcpPacket.ack_num);
				continue;
			}			
			else if ((tcp_packet_decorator.tcpPacket.sequence==SYN_seq_num+1) && (tcp_packet_decorator.tcpPacket.ack_num==SYN_ACK_seq_num+1)){
//				logger.debug("find ack response: "+tcp_packet_decorator.tcpPacket.sequence+" "+tcp_packet_decorator.tcpPacket.ack_num);
				TCP_ACK_Num++;
				if(tcp_packet_decorator.isRetransmissionMerge){
					TCP_ACK_Num+=tcp_packet_decorator.retransmissionMergeAl.size();
				}					
			}
		}
		DL_Data += DL_Retrans_Data;

//		StringBuilder re=new StringBuilder().append(UL_Data).append(";").append(DL_Data).append(";").append(UL_IP_Packet).append(";").append(DL_IP_Packet).append(";").
//				                    append(UL_Disorder_IP_Packet).append(";").append(DL_Disorder_IP_Packet).append(";").
//				                    append(UL_Retrans_IP_Packet).append(";").append(DL_Retrans_IP_Packet).append(";").
//				                    append(UL_IP_FRAG_PACKETS).append(";").append(DL_IP_FRAG_PACKETS).append(";").
//				                    append(TCP_SYN_Num).append(";").append(TCP_SYN_ACK_Num).append(";").append(TCP_ACK_Num).append(";").append(timestamp_DL_Data);
//		logger.info("Http Transaction result: "+re);
	}
	
	//处理重传的数据包，上行数据包direction=0，下行direction=1
	public void RetransPacket_Statistic (TcpPacketDecorator tp, int direction){
		if (direction==0){
			UL_Retrans_IP_Packet+=tp.retransmissionMergeAl.size();//不算重传成功的数据包
			UL_IP_Packet = UL_IP_Packet+tp.retransmissionMergeAl.size();
			for(TcpPacketDecorator tcp_packet_retrans:tp.retransmissionMergeAl){
				UL_Data += tcp_packet_retrans.tcpPacket.length;//上行流量不用和阈值比较，直接累加
			}
		}else{
			DL_Retrans_IP_Packet+=tp.retransmissionMergeAl.size();//不算重传成功的数据包
			DL_IP_Packet = DL_IP_Packet+tp.retransmissionMergeAl.size();
			for(TcpPacketDecorator tcp_packet_retrans:tp.retransmissionMergeAl){
				DL_Retrans_Data += tcp_packet_retrans.tcpPacket.length;//单独记录重传数据包的流量，最后累加。
			}
		}
	}
	
	//处理Tcp分段的数据包，上行数据包direction=0，下行direction=1
	public void ReassemblePacket_Statistic (TcpPacketDecorator tp, int direction){
		if (direction==0){
//			UL_IP_FRAG_PACKETS+=tp.segmentsAl.size()+1;       UL_IP_FRAG_PACKETS计算的是IP分片，而不是TCP分段
			UL_IP_Packet = UL_IP_Packet+tp.segmentsAl.size();
			for(TcpPacketDecorator tcp_packet_segment:tp.segmentsAl){
				if(tcp_packet_segment.isOutOfOrder){
					UL_Disorder_IP_Packet++;
				}
				if (tcp_packet_segment.isRetransmissionMerge){
					this.RetransPacket_Statistic(tcp_packet_segment, 0);
				}
				if(tcp_packet_segment.tcpPacket.more_frag||((!tcp_packet_segment.tcpPacket.more_frag)&&(tcp_packet_segment.tcpPacket.offset!=0))){
					UL_IP_FRAG_PACKETS++;
					logger.debug("find a upload ip frag"+tcp_packet_segment.tcpPacket.sequence);
				}
			}
		}else{
//			DL_IP_FRAG_PACKETS += tp.segmentsAl.size()+1;       UL_IP_FRAG_PACKETS计算的是IP分片，而不是TCP分段
			DL_IP_Packet = DL_IP_Packet + tp.segmentsAl.size();
			for(TcpPacketDecorator tcp_packet_segment:tp.segmentsAl){
				DL_Data += tcp_packet_segment.tcpPacket.length;	
				if((DL_IP_Packet>=max_DL_Data/1480)&&(DL_Data>=max_DL_Data)&&(isOverThreshold==false)){
					isOverThreshold=true;
					timestamp_DL_Data = tcp_packet_segment.tcpPacket.sec*1000+tcp_packet_segment.tcpPacket.usec;
				}
				if(tcp_packet_segment.isOutOfOrder){
					DL_Disorder_IP_Packet++;
				}
				if(tcp_packet_segment.isRetransmissionMerge){
					this.RetransPacket_Statistic(tcp_packet_segment, 1);
				}
				if(tcp_packet_segment.tcpPacket.more_frag||((!tcp_packet_segment.tcpPacket.more_frag)&&(tcp_packet_segment.tcpPacket.offset!=0))){
					DL_IP_FRAG_PACKETS++;
					logger.debug("find a download ip frag"+tcp_packet_segment.tcpPacket.sequence);
				}
			}
		}
	}
}
